
#pragma once
/**
 * 封装Socket
 */

#include <iostream>
#include "Log.hpp"
#include "LockGuard.hpp"
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cstring>
#include <cstdlib>
#include "Err.hpp"

const static int defaultSock = -1;
const static uint16_t defaultPort = 8888;
const static int defaultBack = 32;

namespace yui
{
    class Socket
    {
        public:
            Socket()
                :sock_(defaultSock)
            {
                
            }
            ~Socket()
            {}
            void createSocket()
            {
                sock_ = socket(AF_INET,SOCK_STREAM,0);
                if(sock_ == -1)
                {
                    LOG(FATAL,"socket fail! [%d]->%s",errno,strerror(errno));
                    exit(SOCKET_ERR);
                }
                LOG(DEBUG,"create socket success!");
            }
            //bind端口号
            void Bind(const uint16_t& port)
            {
                struct sockaddr_in local;
                //memset(&local,0,sizeof(local));
                bzero(&local,sizeof(local));

                local.sin_family = AF_INET;
                local.sin_port = htons(port);
                local.sin_addr.s_addr = INADDR_ANY;

                if(bind(sock_,(struct sockaddr*)&local,sizeof(local))==-1)
                {
                    LOG(FATAL,"bind fail [%d]->%s",errno,strerror(errno));
                    exit(BIND_ERR);
                }
                LOG(DEBUG,"bind socket success");
            }
            void Listen()
            {
                if(listen(sock_,defaultBack) == -1)
                {
                    LOG(FATAL,"listen fail [%d]->%s",errno,strerror(errno));
                    exit(LISTEN_ERR);
                }
                LOG(DEBUG,"listen success");
            }

            //处理连接请求
            int Accept(std::string* ip,uint16_t* port)
            {
                struct sockaddr_in client;
                socklen_t len = sizeof(client);

                int retSock = accept(sock_,(struct sockaddr*)&client,&len);
                if(retSock == -1)
                {
                    LOG(WARNING,"accept fail [%d]->%s",errno,strerror(errno));
                }
                else
                {
                    *ip = inet_ntoa(client.sin_addr);
                    *port = ntohs(client.sin_port);
                    LOG(DEBUG,"accept success sock:[%d -> %s:%d]",retSock,ip->c_str(),*port);  
                }
                return retSock;

            }
            //进行连接
            int Connect(const std::string& ip,const uint16_t&port)
            {
                struct sockaddr_in server;
                bzero(&server,sizeof(server));

                server.sin_family = AF_INET;
                server.sin_port = htons(port);
                server.sin_addr.s_addr = inet_addr(ip.c_str());

                return connect(sock_,(struct sockaddr*)&server,sizeof(server));
            }
            void Close()
            {
                if(sock_!=defaultSock)
                    close(sock_);
            }
            int getSock()
            {
                return sock_;
            }
        private:
            int sock_;
    };
}
